
requirejs.config({
    baseUrl: '/js',
});

//doll.js requires signals and jquery to function
requirejs(['lib/signals.min', 'lib/jquery.min', 'engine/doll', 'engine/ui', 'engine/ui/selectable',
           'engine/draw', 'engine/fetch', 'engine/audio', 'engine/input', 'engine/cam',
          'engine/text', 'engine/voxel', 'engine/isosurface', 'engine/perlin',
          'engine/user', 'engine/world'],
          function(signals) {
              //I barely know how I got this but it works
              //console.log = function () {};
              doll.signals = signals;
              var stats, render, camera, scene, clock;
              init();
              add_info();
              setup_audio();
              fill_scene();
              add_stats();
              animate();
         });

function createBlock(geo, x, y, z, bs, bn) {
    x = x || 0;
    y = y || 0;
    z = z || 0;
    bs = bs || 25;
    bn = bn*8 || 0;

    x *= bs*2;
    y *= bs*2;
    z *= bs*2;

    //these 50 are of course 25s
    geo.vertices.push(new THREE.Vector3(x-bs, y-bs, z+bs));//(-50,  -50,   50) 0
    geo.vertices.push(new THREE.Vector3(x+bs, y-bs, z+bs));//( 50,  -50,   50) 1
    geo.vertices.push(new THREE.Vector3(x+bs, y+bs, z+bs));//( 50,   50,   50) 2
    geo.vertices.push(new THREE.Vector3(x-bs, y+bs, z+bs));//(-50,   50,   50) 3

    geo.vertices.push(new THREE.Vector3(x+bs, y-bs, z-bs));//( 50,  -50,  -50) 4
    geo.vertices.push(new THREE.Vector3(x-bs, y-bs, z-bs));//(-50,  -50,  -50) 5     
    geo.vertices.push(new THREE.Vector3(x-bs, y+bs, z-bs));//(-50,   50,  -50) 6
    geo.vertices.push(new THREE.Vector3(x+bs, y+bs, z-bs));//( 50,   50,  -50) 7

    //front
    geo.faces.push(new THREE.Face4(0+bn,1+bn,2+bn,3+bn));
    //back
    geo.faces.push(new THREE.Face4(4+bn,5+bn,6+bn,7+bn));
    //right
    geo.faces.push(new THREE.Face4(1+bn,4+bn,7+bn,2+bn));
    //left
    geo.faces.push(new THREE.Face4(5+bn,0+bn,3+bn,6+bn));
    //top
    geo.faces.push(new THREE.Face4(3+bn,2+bn,7+bn,6+bn));
    //bottom
    geo.faces.push(new THREE.Face4(5+bn,4+bn,1+bn,0+bn));
    
    return geo;
}

var thing, chunk, snobj, wireobj, iso;
var world, moon, user;
function fill_scene() {
    var geo,mat;
/*
    chunk = new doll.voxel.chunk();
    chunk.fill();
    chunk.setup_sphere();
    chunk.buildmesh();
    var co = new THREE.Object3D();
    co.add(chunk.mesh);
    scene.add(co);


    geo = new THREE.Geometry();

    createBlock(geo, 0, 0, 0, 25, 0);
    createBlock(geo, 1, 0, 0, 25, 1);

    mat = new THREE.MeshBasicMaterial({color:0xff00ff});
    thing = new THREE.Mesh(geo, mat);
    
    thing.position.set(-500 + 25, 25, -500 + 25);
    scene.add(thing);

    co.add(thing);
    scene.add(co);
*/

    //lights
    var light = new THREE.SpotLight(0xffffff);
    light.position.set(1000,1000,1000);
    scene.add(light);
    light = new THREE.SpotLight(0xffffff);
    light.position.set(-1000,-1000,-1000);
    scene.add(light);

    var sphere2 = make_volume(
        [[-1.0, 1.0, 0.05],
         [-1.0, 1.0, 0.05],
         [-1.0, 1.0, 0.05]],
        function(x,y,z) {
            return x*x + y*y + z*z - 1.0;
        })();

    var hexagonal_plane = function(x,y,z) { return x + y + z };
    var plane = function(x,y,z) { return y; };
    var terrain =  function(x,y,z) { return  y + PerlinNoise.noise(x*2+5,y*2+3,z*2+0.6); };
    var asteroid = function(x,y,z) { return  (x*x+y*y+z*z) - PerlinNoise.noise(x*2,y*2,z*2); };
    var wat = function(x,y,z) {
        if(Math.abs(x) > Math.abs(y)) {
            if(Math.abs(x) > Math.abs(z)) {
                return x;
            }
            else {
                return z;
            }
        }
        else if(Math.abs(y) > Math.abs(z)) {
            return y;
        }
        else {
            return z;
        }
    };

    var sphere = function(x,y,z) { return Math.sqrt(x*x+y*y+z*z) - 7; };
    var top_sphere = function(x,y,z) { return y > 0 ? Math.sqrt(x*x+y*y+z*z) - 7 : 0; };
    var bottom_sphere = function(x,y,z) { return y < 0 ? Math.sqrt(x*x+y*y+z*z) - 7 : 0; };
    var egg = function(x,y,z) { return Math.sqrt(2*x*x+y*y+z*z) - 7; };
    var cube = function(x,y,z) { return Math.max(x*x,Math.max(y*y,z*z)) - 7; };
    var cone = function(x,y,z) { return y + Math.sqrt(x*x+z*z); };
    var shape = function(x,y,z) { return  Math.sqrt(x*x+y*y+z*z) - 7 - PerlinNoise.noise(x*2,y*2,z*2); };

    var heart = make_volume(
        [[-2.0, 2.0, 0.05],
         [-2.0, 2.0, 0.05],
         [-2.0, 2.0, 0.05]],
        function(x,y,z) {
            y *= 1.5;
            z *= 1.5;
            return Math.pow(2*x*x+y*y+2*z*z-1, 3) - 0.1 * z*z*y*y*y - y*y*y*x*x;
        }
    )();

    user = new doll.user();
    world = new doll.world(
        {
            scene: scene, 
            camera: camera
        });

    world.connect(user);
  
    //isosurface test
    iso = new isosurface( {potential: shape} );
    //iso = new isosurface( {volume: heart} );
    iso.build_mesh();
    iso.object.position.set(0,150,0);
    iso.object.scale.set(100,100,100);
    world.add(iso.object);

/*
    moon = new doll.proc.moon();
    moon.build_surface();
    moon.object.position.set(0,400,0);

    world.add(moon.object);
*/

    scene.add(doll.debug_grid());
}

function add_stats() {
    stats = new Stats();
    stats.setMode(0); // 0: fps, 1: ms

    // Align top-left
    stats.domElement.style.position = 'absolute';
    stats.domElement.style.left = '0px';
    stats.domElement.style.top = '0px';
    document.body.appendChild( stats.domElement );
}

var container
function add_info() {
    container = document.createElement( 'div' );
    document.body.appendChild( container );
    
    var info = document.createElement( 'div' );
    info.style.position = 'absolute';
    info.style.top = '10px';
    info.style.width = '100%';
    info.style.textAlign = 'center';
    info.innerHTML = 'doll.js voxel test <br><strong> click to activate pointerlock </strong>';
    container.appendChild( info );
}

function init() {
    clock = new THREE.Clock();
    scene = new THREE.Scene();
    camera = new doll.cam( 45, window.innerWidth / window.innerHeight, 1, 10000 );
    camera.position.set(0, 300, 1000);
    render = new THREE.WebGLRenderer( {antialias: true} );
    render.setSize( window.innerWidth, window.innerHeight );

    var $view = $('#doll_view');
    $view.append(render.domElement);
    $('canvas').attr('id', '3d_canvas');
    doll.view = $view;
    //document.body.appendChild( render.domElement );

    //config engine
    //should be done with config function in the future
    doll.window = window;
    doll.document = document;
    doll.render = render;
    doll.camera = camera;//current camera global
    doll.scene = scene; //current scene global
    doll.window_width = window.innerWidth;
    doll.window_height = window.innerHeight;
    doll.halfwidth = doll.window_width * 0.5;
    doll.halfheight = doll.window_height * 0.5;

    //init modules order matters will write a nice
    doll.init();
    doll.voxel.init();

    doll.input.on_mouseenter(function(mouse) {
        console.log('Enter', mouse);
    });

    doll.input.on_mouseleave(function(mouse) {
        console.log('Leave', mouse);
    });

    doll.input.on_keydown(function(k) {
        if(k.code == KEY.w && k.shift == true) {
            if(iso) {
                iso.wiremesh.material.wireframe = !iso.wiremesh.material.wireframe;
            }

            if(moon) {
                moon.wiremesh.material.wireframe = !moon.wiremesh.material.wireframe;
            }
        }
    });

    doll.input.on_keydown(function(k) {
        if(k.code == KEY.m) {
            moon.wiremesh.material.wireframe = !moon.wiremesh.material.wireframe;
        }
    });

    //activate user controls
    camera.control();
}

function setup_audio() {
    //loads from assets/audio
    var audio = [
//        'ponponpon.wav',
//        'oniichan_09.ogg',
        'piano_sheet01.ogg'
    ];
    doll.audio.complete = function() {
        console.log('hey I got all my audio');
        //doll.audio.play(0);
    }
    doll.audio.fetch(audio, false);
}

var sample = 0.0;
function animate() {
    doll.fps(60); //lock fps at 60
    doll.tick = (new Date).getTime();

    doll.run = function() {
        var curTime = (new Date).getTime();
        if( curTime < doll.tick) {
            //its not time to step so just render as often as possible
            render.render(scene, camera);
            //doll.voxel.update();//maybe do it while no animations
            //are being calculated?
            requestAnimationFrame(doll.run, render.domElement);
            return;
        }

        //prevent massive frame jumps when user leaves here

        stats.begin();
        //var delta = clock.getDelta();
        var delta = doll.FPS / 1000.0;//convert from ms to seconds passed

        if(sample > 5.0) {
            console.log('FPS: ', 1000.0 / doll.FPS, 'delta: ', delta * 1000);
            sample = 0.0;
        } else {
            sample += delta;
        }

        //set up a frame
        world.update(delta);

        //input after updating camera because update clear move values
        doll.input.update(delta);
        doll.ui.animate(delta);

        render.render(world.scene, world.camera);
        stats.end();
        //next step happens at a fixed time to smooth out the animations
        doll.tick += doll.FPS;
        requestAnimationFrame(doll.run, render.domElement);
    };

    doll.run();
}



